In [2]:
from hashlib import sha256
import json
import ed25519
In [3]:
passphrase = b"witch collapse practice feed shame open despair creek road again ice least"
H = sha256(passphrase)
H.hexdigest()
Out[3]:
In [4]:
H.digest()
Out[4]:
First the private key:
In [5]:
sk = ed25519.SigningKey(H.digest())
sk.to_bytes()
Out[5]:
then the public:
In [6]:
vk = sk.get_verifying_key()
vk.to_bytes()
Out[6]:
In [7]:
tx = {
"type": 0,
"amount": 128,
"senderPublicKey": "Public key of the sender",
"timestamp": "<Timestamp>",
"recipientId": "<Id of the recipient>",
"signature": "<Signature of the data block>",
"id": "<txid>",
"fee": 10000000,
"senderId": "<Id of the sender>",
}
txJSON = json.dumps(tx)
txJSON
Out[7]:
Let $H_{tx}$ be the SHA256 hash of the transaction block.
In [8]:
Htx = sha256(txJSON.encode('ascii'))
Htx.digest()
Out[8]:
Lisk then signs $H_{tx}$ using the sender keys:
In [9]:
sig = sk.sign(Htx.digest(), encoding='hex')
sig
Out[9]:
In [10]:
tx['signature'] = sig.decode('ascii')
tx2JSON = json.dumps(tx)
tx
Out[10]:
In [11]:
Itx = sha256(tx2JSON.encode('ascii'))
sig2 = sk.sign(Itx.digest(), encoding='hex')
sig2
Out[11]:
In [14]:
vk.verify(sig2,Itx.digest(),encoding='hex')
The ID of the transaction (TxID) after the second signature is computed from the SHA256 of the transaction block with the signature(s) appended. The ID is the first 8 bytes of this hash, reversed. Therefore,
Lisk uses the Hashed version of EdDSA, where the message to be signed, is prehashed ($\mathtt{PH}(Tx) = \mathtt{SHA256}(Tx)$) and then signed. This has some advantages:
and disadvantages: